FASM PREPROCESSOR GUIDE


Table of contents:



0. About this document
I wrote this doc because i saw many people are asking many questions on FASM board because not understanding idea or some particular feature of preprocessor. (I dont discourage you to ask anything on forum, not understanding something is not shame and if your question isn't too hard someone will surely reply it). Preprocessor is very finely desribed in FASM manual chapter 2.3 (TODO link). This document was created some time ago, when there was a big confusion within documentation and assembler itself. Now FASM's syntax is simple again (and also much more powerful), and documentation is written well, in similar manner to this guide. But I will try to support you with more examples and special cases. Also don't take this as reference to preprocessor, it's kind-of tutorial.

Please if you can't understand something from this guide tell me about it on my tutorial's thread on FASM board or with email to help me improve it for other people.



1. What is preprocessor
Preprocessor is program (or usualy part of compiler), which modifies your source code before it is compiled. For example, if you use some piece of code very often, you can give it some name, and tell preprocessor to replace name with the piece of code each time.

Another example is, when you want to simulate some instruction which doesn't exist, you can replace it with set of instructions with same effect automatically using preprocessor.

Preprocessor scans source and replaces some things with other. But how you tell it what should it preprocess? For this "preprocessor directives" are used. We will discuss them now.

Preprocessor doesn't know anything about instructions, compiler directives etc., it has it's own set of directives and just ignores parts of source not meant for it.


2. Basic
First I describe basic preprocesing, which is done on file before any other preprocessing.


2.1. Comment ;
Like in most assemblers, comments in FASM start with semicolon (;). Everything up to end of line is ignored and removed from the source.

For example source
;fill 100h bytes at EDI with zeros
xor eax,eax ;zero value in eax
mov ecx,100h/4
rep stosd
will after preprocessing become
xor eax,eax
mov ecx,100h/4
rep stosd

NOTE: ; can be also comprehended as preprocessor operator which deletes text behind it up to end of line.

NOTE: line that contains only comment won't be deleted, like in my example. It will become empty line. I skipped empty line because of text structure. This will be important in next chapter.


2.2. Line Break \
If line seems to be too long for you, you can "break" it with \ symbol (or preprocessor operator). If line ends with \ symbol then next line will be appended to current line.

Example:
db 1,2,3,\
   4,5,6,\
   7,8,9
will be preprocessed to
db 1,2,3,4,5,6,7,8,9

Of course \ inside strings or inside comments doesn't concatenate lines, inside string it is taken as string character (like everything except ending quote) and comments are deleted up to the end of line without inspecting what's inside them.

There can't be anything behind \ in line, except for blank space and comment.

In previous chapter i mentioned that line which contains only comment won't be deleted, it will just become empty line. That means, that code like this:
db 1,2,3,\
;   4,5,6,\   - commented
   7,8,9
will after preprocessing become
db 1,2,3,
7,8,9
and so it will cause error. To solve situation like this, you must put line break before comment:
db 1,2,3,\
\;   4,5,6     - validly commented
   7,8,9
which will become
db 1,2,3,7,8,9
like we wanted.


2.3. Directive include
It's syntax:
include <quoted string - file name>
It will insert text file into sources. It allows you to break source into more files. Of course inserted text will be preprocessed too. File path and name should be quoted (enclosed in ',' or ",").

Examples:
include 'file.asm'
include 'HEADERS\data.inc'
include '..\lib\strings.asm'
include 'C:\config.sys'

You can also access environment variables enclosed in %,%:
include '%FASMINC%\win32a.inc'
include '%SYSTEMROOT%\somefile.inc'
include '%myproject%\headers\something.inc'
include 'C:\%myprojectdir%\headers\something.inc'

To ease creating of multi-OS apps both / and \ always work the same. So for example these are exactly the same
include '%FASMINC%\macro\proc.inc'
include '%FASMINC%/macro/proc.inc'
include '%FASMINC%/macro\proc.inc'
include '%FASMINC%\macro/proc.inc'

TODO: 1.52 paths system (someone could describe it for me...)


2.4. Strings preprocessing
You may have problem to include ' in string declared using 's or " in string declared using "s. For this reason you must place the character twice into string, in that case it won't end string and begin next as you may think, but it will include character into string literaly.

For example:
db 'It''s okay'
will generate binary containing string It's okay.

It's same for ".
db "use apostrophes ("")"


3. Equates

3.1. Directive "equ"
Simplest preprocessor command. It's syntax
<name1> equ <name2>
This command tells preprocessor to replace every following <name1> with <name2>.

Example: source
count equ 10  ;this is preprocessor command
mov ecx,count
is preprocessed to
mov ecx,10

Example:
mov eax,count
count equ 10
mov ecx,count
is preprocessed to
mov eax,count
mov ecx,10
because preprocessor only replaces count behind equ directive.

Even this works:
10 equ 11
mov ecx,10
preprocessed to
mov ecx,11
also note that name1 can be any symbol. Symbol is just set of chars, terminated by blank character (space, tab, end of line) or comment (;) or line-break (\) or operator (including assembly time operators, not only preprocessor's operators). It can't be operator or special symbol (like , or } etc.)

name2 can be anything, not only one symbol, everything up to end of line is taken. It can be even empty, then <name1> is replaced by blank space.

Example:
10 equ 11,12,13
db 10
to
db 11,12,13

Also note that before preprocessor loads equate definition, it replaces all equates at right side of equ, so
b equ a
c equ b
becomes
c equ a
But you can't replace name of equate or equ symbol itself with equate.
a equ equ
1 a 2         
;doesn't work, will remain "1 a 2"
a equ b
a equ 1    
;will declare "a equ 1", not "b equ 1". Redefining 
;equate is used in another manner, read on


3.2. Directive restore
You can also tell preprocessor to stop replacing particular equate. This is done with restore operator:
restore <name>
Where <name> is some equation. Behind this command <name> will no longer be replaced as specified by equ

Example:
mov eax,count
count equ 10
mov eax,count
restore count
mov eax,count
will become
mov eax,count
mov eax,10
mov eax,count
Note that replacements are "stacked" that means if you define two equates for one symbol, and then restore it (once), the first one will be used.

Example:
mov eax,count
count equ 1
mov eax,count
count equ 2
mov eax,count
count equ 3
mov eax,count
restore count
mov eax,count
restore count
mov eax,count
restore count
mov eax,count
to
mov eax,count
mov eax,1
mov eax,2
mov eax,3
mov eax,2
mov eax,1
mov eax,count

If you try to restore non-existing equation nothing will happen.

Example:
mov eax,count
restore count
mov eax,count
to
mov eax,count
mov eax,count


4. Simple macros without arguments


4.1. Simple macro definition
You can create your own instruction / directive using "macro".
macro <name>
{
  <body>
}
After preprocessor finds macro directive, it defines macro, which means each following occurence of line starting with <name> will be replaced by <body>. <name> can be one symbol, <body> can be anything except } which denotes end of macro body.

Example:
macro a
{
  push eax
}
xor eax,eax
a
to
xor eax,eax
push eax

Example:
macro a
{
  push eax
}
macro b
{
  push ebx
}
b
a
to
push ebx
push eax

Of course, macro doesn't have to be indented like in my example, you can use this too:
macro push5 {push dword 5}
push5
to
push dword 5

Or
macro push5 {push dword 5
}
to same result. You are free about indenting macros.


4.2. Redefining macros
You can redefine macros. That means, if you create new macro with name of already existing macro, then the last one is used. But if you use original macro in last one, it will work. Look at example:
macro a {mov ax,5}
macro a
{
  a
  mov bx,5
}
macro a
{
  a
  mov cx,5
}
a
to
mov ax,5
mov bx,5
mov cx,5

Or this example:
macro a {1}
a

macro a {
  2
  a
  2}

a
macro a {
  3
  a
  3}

a
to
1

2
1
2

3
2
1
2
3


4.3. Directive purge (macro undefinition)
You can also undefine macro, like you undefined equate. This is done by purge directive followed by macro name:
a
macro a {1}
a
macro a {2}
a
purge a
a
purge a
a
to
a
1
2
1
a

You can purge more macros with one directive, they must be seperated by comma (,)
macro a {}
macro b {}
purge a,b
or purge one macro more than once to remove more levels of redefinition
macro a {display '1'}
macro a {display '2'}
macro a {display '3'}
purge a,a
a ;displays '1'

If you try to purge non-existing macro nothing will happen.


4.4. Macro behavior
Macro name will be replaced by macro body not only if line is starting with macro, but everywhere where instruction mnemonics (like add, mov) is accepted. It is because main purpose of macro is to simulate instructions. Only exception is instruction prefix (REP, LOCK, etc.), macro is not accepted after instruction prefix.

Example:
macro CheckErr
{
  cmp eax,-1
  jz error
}
call Something
a: CheckErr    ;here macro name is preceded by label definition, but it
	       ;will be replaced
to
call Something
a:
cmp eax,-1
jz error

Example:
macro stos0
{
  mov al,0
  stosb
}
stos0	    ;this is place for instruction, will be replaced
here: stos0 ;this is place for instruciton too
db stos0    ;this in not place for instruction and so won't be replaced
to
mov al,0
stosb
here:
mov al,0
stosb
db stos0

You can also "overload" instruction with macro, because preprocessor doesnt' know about instructions, it allows macro name to be instruction mnemonics.
macro pusha
{
  push eax ebx ecx edx ebp esi edi
}
macro popa
{
  pop edi esi ebp edx ecx ebx eax
}
these 2 save 4 bytes for every pusha because they don't push ESP. But overloading instruction is never good thing, because someone reading your code may get fooled if he don't knows instruction is overloaded.

You can also overload assembly-time directive (eg. non-preprocessor directives):
macro use32
{
  align 4
  use32
}
macro use16
{
  align 2
  use16
}

You also can have equate of same name as macro. Here comes priority problem, when you already have defined macro and you are defining equate of same name, it can be seen as definition of equate or as usage of macro with "equ ..." as arguments (you will learn what are macro arguments later - since chapter 5). It is for example this case:
macro a {}
a equ b
or opposite case can occur, when you have equate defined and are defining macro of same name, you must know if equate will be replaced
a equ b
macro a {}
In first case, macro usage has higher priority than equate definition, so it will throw error that equ b is wrong argument for macroa. In second case macro definiton has higher priority than replacing equate, so macro with name a will be defined (not b). By the way, replacing equate has lowest possible priority, only kind-of exception are equates inside equate definiton, already described by the end of chapter 3.1. But it's always best to have some system in naming which will ensure that you won't happen to have macro and equate of same name.

Also macro contents aren't altered in any way during macro definiton (eg. equates inside them aren't replaced). It makes difference in cases like this:
a equ 0
macro b {a}
a equ 1
b
a equ 2
b
So due to rule it will become
1
2

Also don't forget that after macro is expanded (when used) then this newly created code is also preprocessed, so you can use preprocessor directives inside macro. For example
macro define_equate_a
{
  a equ 1
}
a
define_equate_a
a
will become
a
1


5. Macros with fixed number of arguments


5.1. Macro with one argument
You can also define macro argument. This argument is represented by some symbol, which will be replaced in macro body by passed argument.
macro <name> <argument> { <body> }

Example:
macro add5 where
{
  add where,5
}
add5 ax
add5 [variable]
add5 ds
add5 ds+2
to
add ax,5
add [variable],5
add ds,5 ;there is no such instruction, but its not task of preprocessor
	 ;to check it. It will be preprocessed to this form, and will
	 ;throw error at assembling stage.
add ds+2,5 ;like previous, but this is also syntactically wrong, so it'll
	   ;throw error at parsing stage.
(of course there won't be those comments in preprocessed file :)

Note that all occurences of macro argument inside it's body will be _always_ replaced when it's used, there are no priority issues here. Also, of course, macro arguemnt inside macro's body has higher priority than equate of same name. I believe this is obious enough not to need any examples.


5.2. Macros with more arguments
Macros can have more arguments, separated with comma (,):
macro movv where,what
{
  push what
  pop  where
}
movv ax,bx
movv ds,es
movv [var1],[var2]
preprocessed to
push bx
pop ax
push es
pop ds
push [var2]
pop [var1]

If more macro arguments have same name, first one is used :).
macro a b,b,b
{
  display b
}
a '1','2','3'  ;displays '3'

If you specify less arguments than you listed in macro declaration, then value of not-specified arguments is blank:
macro pupush a1,a2,a3,a4
{
  push a1 a2 a3 a4
  pop a4 a3 a2 a1
}
pupush eax,dword [3]
to
push eax dword [3]
pop dword [3] eax
but, if you want to force argument to have nonblank value, you can place * after it's name in macro definition:
macro a a1,a2*,a3 {}
a 1,2,3 ;works
a 1,2 ;works
a 1,2, ;same as previous
a 1 ;doesn't work
a ,2, ;works
now, macro argument a2 is called "required".

If you want to include comma (,) in macro argument, you must enclose argument in brackets <,>.
macro safe_declare name,what
{
  if used name
    name what
  end if
}
safe_declare var1, db 5
safe_declare array5, <dd 1,2,3,4,5>
safe_declare string, <db "hi, i'm stupid string",0>
to
if used var1
  var1 db 5
end if
if used array5
  array5 dd 1,2,3,4,5
end if
if used string
  string db "hi, i'm stupid string",0
end if

You can use < and > in macro body too, of course:
macro a arg {db arg}
macro b arg1,arg2 {a <arg1,arg2,3>}
b <1,1>,2
is preprocessed to
db 1,1,2,3
this implies that there can be multiple levels of <>s, like in this example usage of macro b is unrolled to a <<1,1>,2,3>. Unfortunately this disallows us (in some cases) to have < and > characters inside value of macro argument.

5.3. Directive "local"
You may want to declare some label inside macro body:
macro pushstr string
{
  call behind ;pushes address of string and jumps to behind
  db string,0
  behind:
}
but if you use this macro twice, label "behind" will be defined twice and this is an error. You can solve this by making label "behind" local to macro. For that preprocessor directive "local" is used.
local <name>

It must be inside macro body. It makes all following occurences of <name> inside macro body local to macro. Thus, if macro is used twice
macro pushstr string
{
  local behind
  call behind
  db string,0
  behind:
}
pushstr 'aaaaa'
pushstr 'bbbbbbbb'
call something
this won't cause any problems. This is done by replacing behind with behind?XXXXXXXX where XXXXXXXX is some hexadecimal number generated by preprocessor. Last example can be for example preprocessed to
call behind?00000001
db 'aaaaa',0
behind?00000001:
call behind?00000002
db 'bbbbbbbb',0
behind?00000002:
call something

Note that you can't directly access names containing ?, as it is special symbol for fasm, for this reason it is used with local names. For example aa?bb is considered as symbol aa, special symbol ? and symbol bb, when you type it this way into source.

If you want more local labels you dont have to use two locals, you can list them all in one local directive, separated by commas (,):
macro pushstr string  ;does same job as previous macro
{
  local addr,behind
  push addr
  jmp behind
  addr db string,0
  behind:
}

It is always good to start all macro local label names with two dots (..) which means they wont change current global label. For example:
macro pushstr string
{
  local behind
  call behind
  db string,0
  behind:
}
MyProc:
  pushstr 'aaaa'
  .a:
will be preprocessed to
MyProc:
call behind?00000001
db 'aaaa',0
behind?00000001:
.a:
and so it will create behind?00000001.a label instead of MyProc.a. But names that start with two dots (..) do not change current global label, so in following case MyProc.a would be declared:
macro pushstr string
{
  local ..behind
  call ..behind
  db string,0
  ..behind:
}
MyProc:
  pushstr 'aaaa'
  .a:


5.4. Operator # (symbol concatenation)
Other fasm's macrolanguage feature is manipulation with symbols. This is done with symbol concatenation operator #, which concatenates two symbols into one, for example a#b will become ab, or aaa bbb#ccc ddd -> aaa bbbccc ddd. This operator can be used only inside macro body, and concatenating symbol will be done after replacing macro arguments, so you can use this to create some symbol from macro argument.

Example:
macro string name, data
{
  local ..start
  ..start:
  name db data,0
  sizeof.#name =  $ - ..start
}
string s1,'macros are stupid'
string s2,<'here i am',13,10,'rock you like a hurricane'>
to
..start?00000001:
s1 db 'macros are stupid',0
sizeof.s1 = $ - ..start?00000001
..start?00000002:
s2 db 'here i am',13,10,'rock you like a hurricane',0
sizeof.s2 = $ - ..start?00000002
so for all strings defined by macro, symbol "sizeof.<name of string> gets defined.

This operator can also concatenate quoted strings:
macro debug name
{
  db 'name: '#b,0
}
debug '1'
debug 'barfoo'
to
db 'name: 1',0
db 'name: barfoo',0
this is usefull when passing argument from macro to macro:
macro pushstring string
{
  local ..behind
  call ..behind
  db string,0
  ..behind:
}
macro debug string
{
  push MB_OK
  push 0 ;empty caption
  pushstring 'debug: '#string  ;"pushstring" takes one argument
  push 0 ;no partent window
  call [MessageBox]
}

Note that you can't use # in arguments of local, because local is processed before #. For that reason, code like this won't work:
macro a arg
{
  local name_#arg
}
a foo

Note that # doesn't work only with adjected words, there can be spaces between them, so a # b is just the same as a#b, which can sometimes cause troubles with empty macro arguments:
macro a b,c 
{
 b#c equ 1
}
a foo,bar ;will properly create equate "foobar equ 1"
a foo ;will create "foo# equ 1" which will become "fooequ 1" and so error


5.5. Operator `
There is also operator ` which transfers symbol following it to quoted string. This operator can be used only inside macro.

Example:
macro proc name
{
  name:
  log `name	  ;log can be some macro which takes string as argument
}
proc DummyProc
to
DummyProc:
log 'DummyProc'

Or one little more complicated example using #:
macro proc name
{
  name:
  log 'entering procedure: '#`name
}
proc DummyProc
retn
proc Proc2
retn
to
DummyProc:
log 'entering procedure: DummyProc'
retn
Proc2:
log 'entering procedure: Proc2'
retn



6. Macros with group argument

6.1. Declaring macro with group argument
Macros can have so-called "group argument". It allows you non-fixed number of arguments. Group argument is enclosed in brackets [,] in macro definition:
macro name arg1,arg2,[grouparg]
{
  <body>
}

Group argument must be last argument in macro defintion. Group argument can contain multiple arguments, like:
macro name arg1,arg2,[grouparg] {}
name 1,2,3,4,5,6
here value of group argument (grouparg) are values 3,4,5 and 6. 1 and 2 are values of arg1 and arg2.

Of course macro can hav only group argument, like:
macro name [grouparg] {}


6.2. Directive common
To work with group arguments, you use some preprocessor directives (common, forward, reverse). These directives can be used only in body of macro with group argument (elsewhere they are ignored). First such directive is common. It means that behind this directive group argument name in macro body will be replaced by all arguments:
macro string [grp]
{
  common
    db grp,0
}
string 'aaaaaa'
string 'line1',13,10,'line2'
string 1,2,3,4,5
to
db 'aaaaaa',0
db 'line1',13,10,'line2',0
db 1,2,3,4,5,0


6.3. Directive forward
But you can work with arguments in group argument separately. For this forward preprocessor directive is used. Part of macro body behind forward directive is preprocessed for each argument in group argument:
macro a arg1,[grparg]
{
forward
  db arg1
  db grparg
}
a 1,'a','b','c'
a -1,10,20
to
db 1
db 'a'
db 1
db 'b'
db 1
db 'c'
db -1
db 10
db -1
db 20

forward is default for macros with group arguments, so previous macro can as well be
macro a arg1,[grparg]
{
  db arg1
  db grparg
}


6.4. Directive reverse
reverse is same as forward, but processess arguments in group argument from last to first:
macro a arg1,[grparg]
{
reverse
  db arg1
  db grparg
}
a 1,'a','b','c'
to
db 1
db 'c'
db 1
db 'b'
db 1
db 'a'


6.5. Combining group control directives
These 3 directives divide macro to blocks. Each block is processed after previous one. For example:
macro a [grparg]
{
  forward
    f_#grparg:	       ;symbol concatenation operator #, see chapter 4.4
  common
    db grparg
  reverse
    r_#grparg:
}
a 1,2,3,4
to
f_1:
f_2:
f_3:
f_4:
db 1,2,3,4
r_4:
r_3:
r_2:
r_1:


6.6. Behavior of directive local inside macro with group argument
There is one more very nice feature with labels local to macro (listed with local preprocessor directive, see chapter 4.3). If local directive is defined inside forward or reverse block, then unique label is defined for each argument in group, and same labels are used for same arguments in following forward or reverse blocks. Example:
macro string_table [string]
{
  forward		  ;table of pointers to strings
    local addr		    ;declare label for this string as local
    dd addr		    ;pointer to string
  forward		  ;strings
    addr db string,0
}
string_table 'aaaaa','bbbbbb','5'
to
dd addr?00000001
dd addr?00000002
dd addr?00000003
addr?00000001 db 'aaaaa',0
addr?00000002 db 'bbbbbb',0
addr?00000003 db '5',0

Another example, with reverse block:
macro a [x]
{
forward
  local here
  here db x
reverse
  dd here
}
a 1,2,3
to
here?00000001 db 1
here?00000002 db 2
here?00000003 db 3
dd here?00000003
dd here?00000002
dd here?00000001
so labels will be used with same arguments in both forward and reverse blocks.

Note that all blocks are processed even if value of group argument is empty
macro count_items [b]
{
  common
    items=0
  forward
    items=items+1
}
count_items 1,eax,stupid_labels,<some other $^!~#$ argument in brackets>  ;after this items = 4
count_items  ;here items=1, not 0, because forward block is processed once anyway
you will learn workaround a little later.


6.7. Macro with multiple group arguments
You can also have more multiple arguments. In that case macro definition wont look like
macro a [grp1],[grp2]
because then it would be unclear which arguments belong to which group. For that reason you declare them like:
macro a [grp1,grp2]
here every odd argument belongs to grp1, every even to grp2.

Example:
macro a [grp1,grp2]
{
  forward
    l_#grp1:
  forward
    l_#grp2:
}
a 1,2,3,4,5,6
to
l_1:
l_3:
l_5:
l_2:
l_4:
l_6:

Another example:
macro ErrorList [name,value]
{
  forward
    ERROR_#name = value
}
ErrorList \
 NONE,0,\
 OUTOFMEMORY,10,\
 INTERNAL,20
to
ERROR_NONE = 0
ERROR_OUTOFMEMORY = 10
ERROR_INTERNAL = 20

Of course there can be more than 2 group arguments:
macro a [g1,g2,g3]
{
  common
    db g1
    db g2
    db g3
}
a 1,2,3,4,5,6,7,8,9,10,11
to
db 1,4,7,10
db 2,5,8,11
db 3,6,9

If you have some of group arguments marked as required (with *, which means such ones cannot have empty value), then value of this argument must be nonblank in each "created" group:
macro a [a1,a2*,a3] {}
a 1,2,3,4,5 ;works, a2 = 2 in first group, 5 in second
a 1,2,3,4   ;doesn't work, a2 is empty in second group
a 1,2,3     ;works, only one group exists
a ,,,4,5    ;doesn't work, group #1 is "created" unless all it's values are empty


7. Pseudo-conditional preprocessing
Until FASM 1.62 there was no real preprocessor conditional syntax in FASM. But assembly-time directive if can be used in conjuction with preprocessor to acheive same results as with preprocessor conditionals (but this way it wastes more time and memory). Even current conditional preprocessing is quite limited, so this is still useful.

As i said, if is assembly-time statement. That means statement is checked after preprocessing, and that allows some special conditional operators to work.

I won't describe it's assembly-time behavior (conditional operators like &, | etc), read FASM's docs for this. I will describe only operators that are used with preprocessor here.


7.1. Operator eq
Simplest is eq. It just compares two symbols if they are same. Value of abcd eq abcd is true, value of abcd eq 1 is false etc. It is useful to compare symbol that will be preprocessed, like:
STRINGS equ ASCII
if STRINGS eq ASCII
  db 'Oh yeah',0
else if STRINGS eq UNICODE
  du 'Oh yeah',0
else
  display 'unknown string type'
end if
after preprocessing it will be
if ASCII eq ASCII
  db 'Oh yeah',0
else if ASCII eq UNICODE
  du 'Oh yeah',0
else
  display 'unknown string type'
end if
so first condition (ASCII eq ASCII) is true, so only db 'Oh yeah',0 will get assembled.

Other case:
STRINGS equ UNICODE	  ;only difference here, UNICODE instead of ASCII
if STRINGS eq ASCII
  db 'Oh yeah',0
else if STRINGS eq UNICODE
  du 'Oh yeah',0
else
  display 'unknown string type'
end if
after preprocessing it will be
if UNICODE eq ASCII
  db 'Oh yeah',0
else if UNICODE eq UNICODE
  du 'Oh yeah',0
else
  display 'unknown string type'
end if
now first condition (UNICODE eq ASCII) will be false, second one (UNICODE eq UNICODE) will be true and so du 'Oh yeah',0 will get assembled.

Better usage of this is checking macro arguments, like
macro item type,value
{
  if type eq BYTE
    db value
  else if type eq WORD
    dw value
  else if type eq DWORD
    dd value
  else if type eq STRING
    db value,0
  end if
}
item BYTE,1
item STRING,'aaaaaa'
to
if BYTE eq BYTE
  db 1
else if BYTE eq WORD
  dw 1
else if BYTE eq DWORD
  dd 1
else if BYTE eq STRING
  db 1,0
end if
if STRING eq BYTE
  db 'aaaaaa'
else if STRING eq WORD
  dw 'aaaaaa'
else if STRING eq DWORD
  dd 'aaaaaa'
else if STRING eq STRING
  db 'aaaaaa',0
end if
so only these two commands will get assembled:
db 1
db 'aaaaaa',0

eq (like all other preprocessor operators) can also work with blank arguments. That means, for example, that if eq is true, and if 5 eq is false etc. Example macro:
macro mov dest,src,src2
{
  if src2 eq
    mov dest,src
  else
    mov dest,src
    mov src,src2
  end if
}


7.2. Operator eqtype
Other operator is eqtype. It compares whether symbols are of same type. Types are:
- individual quoted strings (those not being a part of numerical expression)
- floating point numbers
- any numerical expression (note that any unknown word will be treated as label, so it also will be seen as such expression)
- addresses - the numerical expressions in square brackets (with size operators and segment prefixes)
- instruction mnemonics
- registers
- size operators
- near/far operators,
- use16/use32/use64 operators
- any special character (, , /, etc..) is separate type
- blank space

Example of macro which allows SHL instruction with memory variable as count, like shl ax,[myvar]
macro shl dest,count
{
  if count eqtype [0]	;if count is memory variable
    push cx
    mov cl,count
    shl dest,cl
    pop cx
  else			;if count is of another type
    shl dest,count	;just use original shl
  end if
}
shl ax,5
byte_variable db 5
shl ax,[byte_variable]
to
if 5 eqtype [0]
  push cx
  mov cl,5
  shl ax,cl
  pop cx
else
  shl ax,5
end if
byte_variable db 5
if [byte_variable] eqtype [0]
  push cx
  mov cl,[byte_variable]
  shl ax,cl
  pop cx
else
  shl ax,[byte_variable]
end if
and so, due to conditions, it will be assembled to
shl ax,5
byte_variable db 5
push cx
mov cl,[byte variable]
shl ax,cl
pop cx
Note that shl ax,byte [variable] wouldn't work with this macro, because condition byte [variable] eqtype [0] isn't true, read further.

eqtype operands doesn't work only with two operands. It just compares whether types of operands on left side and same to type of operands on right side of eqtype. For example if eax 4 eqtype ebx name is true (name is label and thus it is number too).

Example of extending mov intruction so it allows moving between memory variables:
macro mov dest,src
{
  if dest src eqtype [0] [0]
    push src
    pop dest
  else
    mov dest,src
  end if
}
mov [var1],5
mov [var1],[var2]
will be preprocessed to
if [var1] 5 eqtype [0] [0]  ;false
  push 5
  pop [var1]
else
  mov [var1],5
end if
if [var1] [var2] eqtype [0] [0]  ;true
  push [var2]
  pop [var1]
else
  mov [var1],[var2]
end if
and assembled to
mov [var1],5
push [var2]
pop [var1]
Anyway, better (more readable) way to write such macro is to use & operator (not described in this document, see FASM documentation), like:
macro mov dest,src
{
  if (dest eqtype [0]) & (src eqtype [0])
    push src
    pop dest
  else
    mov dest,src
  end if
}
above example using eqtype with four arguments was meant only to demonstrate possibilities, & should be used if possible.

Note that currently you can use incomplete expressions as argument of eqtype, it is sufficent if parser recognizes it's type, but this is undocumented behavior so i won't describe it anymore.


7.3. Operator "in"
FASM also includes another operator. It can be used if you use more eqs:
macro mov a,b
{
  if (a eq cs) | (a eq ds) | (a eq es) | (a eq fs) |\
     (a eq gs) | (a eq ss)
    push b
    pop a
  else
    mov a,b
  end if
}
Instead of many |ed eqs, you can use in operator. It compares symbol on the left side with more symbols in list on the right side. Symbol list must be enclosed in brackets ("<" and ">"), symbols inside list should be separated with comma (,).
macro mov a,b
{
  if a in <cs,ds,es,fs,gs,ss>
    push b
    pop a
  else
    mov a,b
  end if
}

in also works with more symbols on both sides (like eq):
if dword [eax] in <[eax], dword [eax], ptr eax, dword ptr eax>


8. Structures
Structures in FASM aren't really structures, they are "named macros", which is thing that can be easily used to define structure (you'll see). You declare them with struc directive:
struc <name> <arguments> { <body> }

Structure is almost exactly the same as macro. Difference is that when you use structure in code (create instance of structure), it must be preceded by some label (instance name). For example
struc a {db 5}
a
doesn't work. Structure is only recognized when preceded by name, like:
struc a {db 5}
name a
will, like macro, get preprocessed to
db 5

Reason of instance name (the one before structure) is, that it will be automatically declared at the beginning of structure and also appended before every symbol inside structure body which is starting with dot (.). For example:
struc a {.local:}
name1 a
name2 a
will be
name1:
name1.local:
name2:
name2.local:

This way you can define something like structures you know from other languages. Example:
struc rect left,right,top,bottom  ;has arguments, like macros
{
  .left dd left
  .right dd right
  .top dd top
  .bottom dd bottom
}
r1 rect 0,20,10,30
r2 rect ?,?,?,?
to
r1:
r1.left dd 0
r1.right dd 20
r1.top dd 10
r1.bottom dd 30
r2:
r2.left dd ?
r2.right dd ?
r2.top dd ?
r2.bottom dd ?

You can also use nice trick with which you don't have to specify arguments (and 0 will be used instead):
struc ymmud arg
{
  .member dd arg+0
}
y1 ymmud 0xACDC
y2 ymmud
to
y1:
y1.member dd 0xACDC+0
y2:
y2.member dd +0
as described in 4.2, if argument is not specified it's value is blank inside macro/structure body. We also used that + is both binary (with two operands) and unary (with one operand) operator.

If you want to define the instance name label yourself, then you can use . symbol somewhere inside structure. Instance name then won't be defined automatically, and every occurence of . will be replaced by structure instance name.
struc rw howmuch*
{ . rw howmuch
  sizeof#. = $ - .
}
mydata rw 5 ;defines also constant "sizeof.mydata" with value 10
rw 5 ;still works, this is not instance of structure, original rw is used
symbols starting with dot will have instance name prepended whether you use "." inside structure or not.

Structures can be redefined just like macros (they ARE just like macros), so structure definitions can be nested in same manner. This can be used to extend (inherit) structures:
struc a a1,a2
{ .a1 dd a1
  .a2 dd a2
}
struc a a1,a2,a3
{ . a a1,a2 ;original "a", named same as current structure
  .a3 dd a3 ;new member
}

Structures are undefined with restruc directive. It is same thing as purge for macros so i believe it doesn't need any further description.
struc a a1,a2
{ .a1 dd a1
  .a2 dd a2
}
struc a a1,a2,a3
{ . a a1,a2 ;original "a", named same as current structure
  .a3 dd a3 ;new member
}
kokot1 a 1,2,3 ;works
restruc a
kokot2 a 1,2,3 ;doesn't work anymore
kokot3 a 1,2 ;but this still does

NOTE: There is defined standard macro called struct (not struc), which declares structure (in past it was extending structure declaration). Don't mistake struct with struc. I personally suggest you to use struct macros to define data structures, they solve many issues and allow much more. You can find them in FASM's include directory in macros/struct.inc.



REST WILL BE ADDED ?SOON?



FINAL WORDS
Don't forget to read FASM documentation. Almost everything from this tutorial is there, maybe writen in way little harder for learning but better as reference.